/**
 * Copyright (c) 2018-2023, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 *
 * Contains: 
 *
 * Change Logs:
 * Date           Author            Notes
 * 2023-07-15     Shiroko           Init
 */
#ifndef __DRIVERS_VIRTIO_VIRTIO_PCI_PRIVATE_H__
#define __DRIVERS_VIRTIO_VIRTIO_PCI_PRIVATE_H__

#include <nxos.h>
#include <pci.h>

/* VIRTIO PCI Definitions */
/*
 * PCI Specification:
 * https://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.html#x1-1150001
 */
#define VIRTIO_PCI_VENDOR_ID 0x1AF4
enum VirtioPCI_TransitionalDeviceId
{
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_START        = 0x1000,
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_NETWORK_CARD = 0x1000,
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_BLOCK,
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_MEMORY_BALLOONING,
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_CONSOLE,
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_SCSI_HOST,
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_ENTROPY_SOURCE,
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_9P_TRANSPORT = 0x1009,
    VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_END          = 0x103F,
};
typedef enum VirtioPCI_TransitionalDeviceId VirtioPCI_TransitionalDeviceId;

#define VIRTIO_PCI_DEVICE_ID_IS_TRANSITIONAL(x) ((x) <= VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_END && (x) >= VIRTIO_PCI_DEVICE_ID_TRANSITIONAL_START)
#define MAKE_VIRTIO_PCI_DEVICE_ID(x) ((x) + 0x1040)
#define GET_VIRTIO_DEVICE_ID_FROM_PCI(x) ((x) - 0x1040)

struct VirtioPCICapacity
{
    NX_U8  vendor;
    NX_U8  next;
    NX_U8  length_cap;
    NX_U8  type;
    NX_U8  bar;
    NX_U8  id;
    NX_U8  padding[2];
    NX_U32 offset;
    NX_U32 length;
    char   additional_field[0];
};
typedef struct VirtioPCICapacity            VirtioPCICapacity;
#define VIRTIO_PCI_CAPACITY_VENDOR  0x09

enum VirtioPCICapacityType
{
    VIRTIO_PCI_CAPACITY_COMMON_CFG        = 1,
    VIRTIO_PCI_CAPACITY_NOTIFY_CFG,
    VIRTIO_PCI_CAPACITY_ISR_CFG,
    VIRTIO_PCI_CAPACITY_DEVICE_CFG,
    VIRTIO_PCI_CAPACITY_PCI_CFG,
    VIRTIO_PCI_CAPACITY_SHARED_MEMORY_CFG = 8,
    VIRTIO_PCI_CAPACITY_VENDOR_CFG,
};
typedef enum VirtioPCICapacityType          VirtioPCICapacityType;

struct VirtioPCICommonCfg
{
    NX_U32 device_feature_select;     /* read-write */
    NX_U32 device_feature;            /* read-only for driver */
    NX_U32 driver_feature_select;     /* read-write */
    NX_U32 driver_feature;            /* read-write */
    NX_U16 config_msix_vector;        /* read-write */
    NX_U16 num_queues;                /* read-only for driver */
    NX_U8  device_status;             /* read-write */
    NX_U8  config_generation;         /* read-only for driver */

    /* About a specific virtqueue. */
    NX_U16 queue_select;              /* read-write */
    NX_U16 queue_size;                /* read-write */
    NX_U16 queue_msix_vector;         /* read-write */
    NX_U16 queue_enable;              /* read-write */
    NX_U16 queue_notify_off;          /* read-only for driver */
    NX_U64 queue_desc;                /* read-write */
    NX_U64 queue_driver;              /* read-write */
    NX_U64 queue_device;              /* read-write */
    NX_U16 queue_notify_data;         /* read-only for driver */
    NX_U16 queue_reset;               /* read-write */
};
typedef struct VirtioPCICommonCfg           VirtioPCICommonCfg;

struct VirtioPCIMappedBar
{
    NX_List         list;
    NX_PciDeviceBar *bar;
};
typedef struct VirtioPCIMappedBar           VirtioPCIMappedBar;

struct VirtioPCIExtension
{
    NX_PciDevice       *pciDevice;
    VirtioPCICommonCfg *commonCfg;
    void               *queueNotifyBase;
    NX_U32             queueNotifyMultiplier;
    /* Bit 0: Queue Interrupt, Bit 1: Device configuration Interrupt */
    NX_U32             *isrStatus; // We're not using MSI-X, this field is available
    void               *deviceCfg;
    NX_List            mappedBarListHead;
};
typedef struct VirtioPCIExtension           VirtioPCIExtension;

#endif // __DRIVERS_VIRTIO_VIRTIO_PCI_PRIVATE_H__
